/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Armin Lunkeit
 *
 * This implementation is part of math-core
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
//
//  matrix.h
//  math-core
//
//  Created by Armin Lunkeit on 15.02.14.
//  Copyright (c) 2014 Armin Lunkeit. All rights reserved.
//

#ifndef math_core_matrix_h
#define math_core_matrix_h

#include <stdint.h>
#include <sstream>
#include <array>
#include <vector>
#include "fraction.h"

typedef std::vector<PFraction> PFArray;
typedef std::vector< PFArray > FMatrix;

class Matrix
{
public:
    
    /**
     *
     * @param n - The count of rows in the matrix
     * @param m - the count of columns in the matrix
     */
    Matrix( uint32_t n, uint32_t m );
    ~Matrix();
    
    Matrix( Matrix const& orig );
    
    uint32_t row() const
    { return _n; }
    
    uint32_t columns() const
    { return _m; }
    
    PFArray& operator[](uint32_t const& index);
    /**
     * Transpose operation. This operation works on this
     */
    void transpose();
    
    /**
     * Multiply all values with a scalar value
     */
    void multiplyScalar( uint32_t s );

    /**
     * Returns a matrix of the values in the requested column.
     */
    Matrix getColumn( uint32_t col ) const throw( std::runtime_error);
    
    /**
     * Returns a row with the requested values
     */
    Matrix getRow( uint32_t row ) const throw( std::runtime_error);
    
    /**
     * Do matrix multiplication
     */
    Matrix operator * ( Matrix const& m ) const;
    
protected:
    
    
    Matrix& operator = ( Matrix const& rhs );
    
    uint32_t _n;
    
    uint32_t _m;
    
    FMatrix _fmatrix;

	// print values of matrix to stream
    friend std::ostream& operator<<(std::ostream& lhs, Matrix const& rhs);
};

std::ostream& operator<<(std::ostream& lhs, Matrix const& rhs);

#endif
